package com.lyf.scm.plan.domain.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.lyf.scm.common.constants.BigDataEsConstants;
import com.lyf.scm.common.enums.EsConmulEnum;
import com.lyf.scm.common.enums.RequirementPlanEnum;
import com.lyf.scm.common.enums.ResponseMsg;
import com.lyf.scm.plan.config.ElasticSearchConfiguration;
import com.lyf.scm.plan.domain.remote.basedata.dto.StoreDTO;
import com.lyf.scm.plan.domain.remote.stock.facade.StockCoreFacade;
import com.lyf.scm.plan.domain.repository.RequirementConfirmationRepository;
import com.lyf.scm.plan.domain.service.BigDataEsRequirementService;
import com.lyf.scm.plan.domain.service.CommonService;
import com.lyf.scm.plan.domain.util.BigDataCacheUtil;
import com.lyf.scm.plan.insfrastructure.db.dataobject.RequirementConfirmationDO;
import com.lyf.scm.plan.insfrastructure.db.dataobject.es.BigdataPredictlyEsEntity;
import com.lyf.scm.plan.insfrastructure.db.dataobject.es.SalesPlanEsEntity;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.InternalTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.sum.InternalSum;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ScrolledPage;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.lyf.scm.common.constants.CommonConstants.REDIS_CACHE_REQUIREMENT;
import static com.lyf.scm.common.enums.RequirementPlanEnum.*;
import static com.lyf.scm.common.util.BatchHandlerUtil.splitTo;
import static com.lyf.scm.plan.domain.util.BigDataCacheUtil.*;
import static com.lyf.scm.plan.domain.util.BigDataCacheUtil.startDateStr12;
import static java.math.BigDecimal.ROUND_HALF_UP;
import static java.util.stream.Collectors.groupingBy;
import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * es解决方案---需求计划
 *
 * @author wangchlei
 * @date 2020/10/30
 */
@Slf4j
@Service
public class BigDataEsRequirementServiceImpl implements BigDataEsRequirementService {
    @Resource
    private StockCoreFacade stockCoreFacade;
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    @Resource
    private RequirementConfirmationRepository requirementConfirmationRepository;
    @Resource
    private CommonService commonService;

    private static final String SALES_PLAN_INDEX_NAME = "scm_plan_sales_requirement_";

    /**
     * 执行大数据任务
     *
     * @param
     * @return void
     **/
    @Override
    public void handleApiDispatcher() {
        Date date = new Date();
        String specifiedDate = DateUtil.formatDate(DateUtil.beginOfWeek(date));
        long startTime = System.currentTimeMillis();
        if (!validWeekJob(date)) {
            return;
        }
        String indexName = SALES_PLAN_INDEX_NAME + specifiedDate.replace("-", "");
        List<StoreDTO> storeDTOS = stockCoreFacade.queryFactoryByRwType(16);
        log.info("\n【大数据需求计划Job】：已获取所有仓库,仓库数量 {}", storeDTOS.size());
        this.initCacheData(date);
        log.info("\n【大数据需求计划Job】：开始处理所有仓库");
        storeDTOS.forEach(item -> this.handleWarehouse(item.getCode(), indexName));
        elasticsearchTemplate.refresh(SalesPlanEsEntity.class);
        //清空缓存
        commonService.clearCache(REDIS_CACHE_REQUIREMENT);
        long endTime = System.currentTimeMillis();
        this.writeOperateLog(endTime - startTime);
        log.info("\n【大数据需求计划Job】：执行完毕");
        //将本地格式化后的es数据同步到mysql
        //storeDTOS.forEach(item -> this.handleWarehouseConfirmQty(item.getCode()));
    }

    /**
     * 插入操作日志
     *
     * @param
     * @return void
     **/
    private void writeOperateLog(Long time) {
        JSONObject kibanaJson = new JSONObject();
        //日志类型
        kibanaJson.put("logType", "\t\n" +
                "大数据JOB操作日志（需求计划）");
        //操作状态：成功/失败
        kibanaJson.put("status", "success");
        //时长
        kibanaJson.put("timeSize", time + "ms");
        log.info(kibanaJson.toString());
    }

    @Override
    public void triggerJob() {
        Date date = new Date();
        String specifiedDate = DateUtil.formatDate(DateUtil.beginOfWeek(date));
        List<StoreDTO> storeDTOS = stockCoreFacade.queryFactoryByRwType(16);
        String indexName = SALES_PLAN_INDEX_NAME + specifiedDate.replace("-", "");
        log.info("\n【大数据需求计划Job】：已获取所有仓库,仓库数量 {}", storeDTOS.size());
        this.initCacheData(date);
        log.info("\n【大数据需求计划Job】：开始处理所有仓库");
        storeDTOS.forEach(item -> this.handleWarehouse(item.getCode(), indexName));
        elasticsearchTemplate.refresh(SalesPlanEsEntity.class);
        //清空缓存
        commonService.clearCache(REDIS_CACHE_REQUIREMENT);
        log.info("\n【大数据需求计划Job】：执行完毕");
    }

    /**
     * 处理mysql确认量表
     *
     * @param warehouseCode
     * @return void
     **/
    private void handleWarehouseConfirmQty(String warehouseCode) {
        //获取基础es中的分组查询条件：按照仓库和sku分组，聚合13周预测值
        SearchQuery searchQuery = this.getSearchQuery(warehouseCode);
        Aggregations aggregations;
        //查询es
        try {
            aggregations = elasticsearchTemplate.query(searchQuery, SearchResponse::getAggregations);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("\n【大数据需求计划Job】：(Mysql)仓库数据处理失败：code {}", warehouseCode + " 失败原因：拉取大数据es数据失败");
            return;
        }
        //根据仓库，日期条件从mysql获取需要更新或数据
        List<RequirementConfirmationDO> requirementConfirmationDOs;
        try {
            requirementConfirmationDOs = requirementConfirmationRepository.pullDataByWarehouse(warehouseCode, startDate1, endDate12);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("\n【大数据需求计划Job】：(Mysql)仓库数据处理失败：code {}", warehouseCode + " 失败原因：拉取mysql数据失败");
            return;
        }
        List<RequirementConfirmationDO> upDO = new ArrayList<>();
        List<RequirementConfirmationDO> inDO = new ArrayList<>();
        try {
            this.dealWithReault(warehouseCode, aggregations, requirementConfirmationDOs, upDO, inDO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("\n【大数据需求计划Job】：(Mysql)仓库数据处理失败：code {}", warehouseCode + " 失败原因：数据处理失败");
            return;
        }
        try {
            requirementConfirmationRepository.handleResult(inDO, upDO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("\n【大数据需求计划Job】：(Mysql)仓库数据处理失败：code {}", warehouseCode + " 失败原因：mysql数据处理失败");
        }

    }

    private void dealWithReault(String warehouseCode, Aggregations aggregations, List<RequirementConfirmationDO> requirementConfirmationDOs, List<RequirementConfirmationDO> upDO, List<RequirementConfirmationDO> inDO) {
        Map<String, Aggregations> skuAggregationsMap = getSubAggregations(aggregations, RequirementPlanEnum.GROUP_SKU.getType());
        Map<String, Aggregation> sumMap;
        String skuCode;
        int count;
        for (Map.Entry<String, Aggregations> skuEntry : skuAggregationsMap.entrySet()) {
            count = 0;
            skuCode = skuEntry.getKey();
            sumMap = skuEntry.getValue().asMap();
            for (RequirementConfirmationDO item : requirementConfirmationDOs) {
                if (skuCode.equals(item.getSkuCode())) {
                    this.updateConfirmQty(item, sumMap);
                    upDO.add(item);
                    count++;
                }
            }
            if (count == 0) {
//新增13周数据
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_1_GROUP.getType())).getValue()), startDate1));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_2_GROUP.getType())).getValue()), startDate2));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_3_GROUP.getType())).getValue()), startDate3));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_4_GROUP.getType())).getValue()), startDate4));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_5_GROUP.getType())).getValue()), startDate5));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_6_GROUP.getType())).getValue()), startDate6));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_7_GROUP.getType())).getValue()), startDate7));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_8_GROUP.getType())).getValue()), startDate8));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_9_GROUP.getType())).getValue()), startDate9));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_10_GROUP.getType())).getValue()), startDate10));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_11_GROUP.getType())).getValue()), startDate11));
                inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_12_GROUP.getType())).getValue()), startDate12));
            }
            inDO.add(this.addNewRecording(warehouseCode, skuCode, BigDecimal.valueOf(((InternalSum) sumMap.get(SALES_WEEK_F_13_GROUP.getType())).getValue()), startDate13));

        }
    }

    private RequirementConfirmationDO addNewRecording(String warehouseCode, String skuCode, BigDecimal sales, Date date) {
        RequirementConfirmationDO item = new RequirementConfirmationDO();
        item.setPlanStartDate(date);
        item.setWarehouseCode(warehouseCode);
        item.setSkuCode(skuCode);
        item.setSupplyChainConfirmationQty(sales);
        return item;
    }

    /**
     * 更新该条记录，设置本次供应链确认量
     *
     * @param item
     * @param sumMap
     * @return void
     **/
    private void updateConfirmQty(RequirementConfirmationDO item, Map<String, Aggregation> sumMap) {
        Date startDate = item.getPlanStartDate();
        if (startDate1.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_1_GROUP.getType()));
            return;
        }
        if (startDate2.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_2_GROUP.getType()));
            return;
        }
        if (startDate3.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_3_GROUP.getType()));
            return;
        }
        if (startDate4.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_4_GROUP.getType()));
            return;
        }
        if (startDate5.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_5_GROUP.getType()));
            return;
        }
        if (startDate6.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_6_GROUP.getType()));
            return;
        }
        if (startDate7.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_7_GROUP.getType()));
            return;
        }
        if (startDate8.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_8_GROUP.getType()));
            return;
        }
        if (startDate9.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_9_GROUP.getType()));
            return;
        }
        if (startDate10.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_10_GROUP.getType()));
            return;
        }
        if (startDate11.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_11_GROUP.getType()));
            return;
        }
        if (startDate12.equals(startDate)) {
            this.setConfirmQty(item, (InternalSum) sumMap.get(SALES_WEEK_F_12_GROUP.getType()));
        }
    }

    private void setConfirmQty(RequirementConfirmationDO item, InternalSum sales) {
        item.setLastConfirmQty(item.getSupplyChainConfirmationQty());
        item.setSupplyChainConfirmationQty(BigDecimal.valueOf(sales.getValue()));
    }

    /**
     * 获取下级聚合数据
     *
     * @param aggregations
     * @param subKey
     * @return 返回map，key是下级指标，值是聚合Aggregations对象
     */
    private Map<String, Aggregations> getSubAggregations(Aggregations aggregations, String subKey) {
        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        StringTerms stringTerms = (StringTerms) aggregationMap.get(subKey);
        List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
        return buckets.stream().collect(Collectors.toMap(bucket -> (String) bucket.getKey(), InternalTerms.Bucket::getAggregations));
    }

    /**
     * 获取基础es中的分组查询条件：按照仓库和sku分组，聚合13周预测值
     *
     * @param warehouseCode
     * @return {@link SearchQuery}
     **/
    private SearchQuery getSearchQuery(String warehouseCode) {
        //获取es过滤条件
        BoolQueryBuilder queryBuilder = this.getBoolQueryBuilder(warehouseCode);
        //获取es分组条件:按照sku
        AbstractAggregationBuilder<TermsAggregationBuilder> aggregationBuilder = this.getAggregationBuilder();
        return new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withIndices(ElasticSearchConfiguration.getIndex())
                .addAggregation(aggregationBuilder)
                .build();
    }

    /**
     * 获取es分组条件:按照sku
     *
     * @param
     * @return {@link AbstractAggregationBuilder<TermsAggregationBuilder>}
     **/
    private AbstractAggregationBuilder<TermsAggregationBuilder> getAggregationBuilder() {
        TermsAggregationBuilder termSku = AggregationBuilders.terms(RequirementPlanEnum.GROUP_SKU.getType())
                .field(RequirementPlanEnum.SKU_KEY.getType() + ".keyword").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        termSku.subAggregation(AggregationBuilders.sum(SALES_WEEK_F_1_GROUP.getType()).field(SALES_WEEK_F_1.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_2_GROUP.getType()).field(SALES_WEEK_F_2.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_3_GROUP.getType()).field(SALES_WEEK_F_3.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_4_GROUP.getType()).field(SALES_WEEK_F_4.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_5_GROUP.getType()).field(SALES_WEEK_F_5.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_6_GROUP.getType()).field(SALES_WEEK_F_6.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_7_GROUP.getType()).field(SALES_WEEK_F_7.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_8_GROUP.getType()).field(SALES_WEEK_F_8.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_9_GROUP.getType()).field(SALES_WEEK_F_9.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_10_GROUP.getType()).field(SALES_WEEK_F_10.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_11_GROUP.getType()).field(SALES_WEEK_F_11.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_12_GROUP.getType()).field(SALES_WEEK_F_12.getType()))
                .subAggregation(AggregationBuilders.sum(SALES_WEEK_F_13_GROUP.getType()).field(SALES_WEEK_F_13.getType()));
        return termSku;
    }

    /**
     * 获取es过滤条件:仓库类型，仓库编码，日期
     *
     * @param warehouseCode
     * @return {@link BoolQueryBuilder}
     **/
    private BoolQueryBuilder getBoolQueryBuilder(String warehouseCode) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        return queryBuilder.filter(matchQuery(RequirementPlanEnum.NODE_ID.getType(), warehouseCode)).filter(matchQuery(RequirementPlanEnum.DATE.getType(), startDateStr1));
    }

    /**
     * 处理每一个仓库
     *
     * @param warehouseCode
     * @return void
     **/
    private void handleWarehouse(String warehouseCode, String indexName) {
        //首先获取该仓库下所有存在的sku，调用大数据接口
        List<String> skuCodes = this.getAllSkuFromBigDataPlanSales(warehouseCode, indexName);
        List<IndexQuery> queryList;
        //大数据信息
        List<BigdataPredictlyEsEntity> bigDataPlanSalesEntitys;
        try {
            //以sku和仓库code为单位更新数据
            for (String skuCode : skuCodes) {
                //获取查询条件
                bigDataPlanSalesEntitys = this.getBigDataPlanSales(warehouseCode, skuCode, indexName);
                if (!CollectionUtils.isEmpty(bigDataPlanSalesEntitys)) {
                    queryList = this.getResult(warehouseCode, skuCode, bigDataPlanSalesEntitys);
                } else {
                    log.warn("\n【大数据需求计划Job】：仓库数据无数据：code {} sku {}", warehouseCode, skuCode);
                    return;
                }
                this.handleBigData(queryList);
                log.info("\n【大数据需求计划Job】：仓库：{} 商品：{} 处理完毕", warehouseCode, skuCode);
            }
        } catch (feign.RetryableException retryableException) {
            retryableException.printStackTrace();
            this.writeErrorLog(warehouseCode, retryableException.getMessage());
            return;
        } catch (Exception e) {
            e.printStackTrace();
            this.writeErrorLog(warehouseCode, ResponseMsg.FAIL_5004.getMsg());
            return;
        }
        log.info("\n【大数据需求计划Job】：仓库：{} 处理完毕", warehouseCode);
    }

    private List<String> getAllSkuFromBigDataPlanSales(String warehouseCode, String indexName) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .filter(matchQuery(NODE_ID.getType(), warehouseCode));
        //获取AggregationBuilders
        TermsAggregationBuilder groupSku = AggregationBuilders.terms(BigDataEsConstants.GROUP_SKU)
                .field(EsConmulEnum.SKU_KEYWORD.getFName()).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        SearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withIndices(indexName)
                .addAggregation(groupSku)
                .withPageable(PageRequest.of(0, 1))
                .build();
        AggregatedPage<BigdataPredictlyEsEntity> esEntities = elasticsearchTemplate.queryForPage(query, BigdataPredictlyEsEntity.class);
        return parsingData(esEntities);
    }

    /**
     * 解析ES返回结果
     *
     * @param entities
     * @return
     */
    private List<String> parsingData(AggregatedPage<BigdataPredictlyEsEntity> entities) {
        List<String> list = new ArrayList<>();
        StringTerms stringTerms = (StringTerms) entities.getAggregation(BigDataEsConstants.GROUP_SKU);
        List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
        // 解析
        String skuCode;
        for (StringTerms.Bucket item : buckets) {
            skuCode = item.getKey().toString();
            if (skuCode != null) {
                list.add(skuCode);
            }
        }
        return list;
    }

    private void writeErrorLog(String warehouseCode, String message) {
        JSONObject kibanaJson = new JSONObject();
        //日志类型
        kibanaJson.put("logType", "\t\n" +
                "大数据JOB操作日志（需求计划）");
        //操作状态：成功/失败
        kibanaJson.put("status", "error");
        //门店编码
        kibanaJson.put("warehouseCode", warehouseCode);
        //错误信息
        kibanaJson.put("msg", message);
        log.error(kibanaJson.toString());
    }

    /**
     * 将结果写入es
     *
     * @param queryList
     * @return void
     **/
    private void handleBigData(List<IndexQuery> queryList) {
        if (!CollectionUtils.isEmpty(queryList)) {
            List<List<IndexQuery>> lists = splitTo(queryList, 5000);
            for (List<IndexQuery> list : lists) {
                elasticsearchTemplate.bulkIndex(list);
            }
        }
    }

    /**
     * 获取大数据备份的es数据
     *
     * @param warehouseCode
     * @return {@link List<BigdataPredictlyEsEntity>}
     **/
    private List<BigdataPredictlyEsEntity> getBigDataPlanSales(String warehouseCode, String skuCode, String indexName) {
        final long SCROLL_TIMEOUT = 5 * 60 * 1000;
        // 获取所有周查询条件条件查询
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(
                        QueryBuilders.boolQuery()
                                .filter(matchQuery(NODE_ID.getType(), warehouseCode)).filter(matchQuery(SKU_KEY.getType(), skuCode))
                ).withIndices(indexName).withPageable(PageRequest.of(0, 1000)).build();
        ScrolledPage<BigdataPredictlyEsEntity> scroll = (ScrolledPage<BigdataPredictlyEsEntity>) elasticsearchTemplate
                .startScroll(SCROLL_TIMEOUT, searchQuery, BigdataPredictlyEsEntity.class);
        List<BigdataPredictlyEsEntity> bigDataGeneralInfoDTOs = new ArrayList<>();
        while (scroll.hasContent()) {
            bigDataGeneralInfoDTOs.addAll(scroll.getContent());
            scroll = (ScrolledPage<BigdataPredictlyEsEntity>) elasticsearchTemplate.continueScroll(
                    scroll.getScrollId(), SCROLL_TIMEOUT, BigdataPredictlyEsEntity.class);
        }
        //根据所有查询条件获取数据
        return bigDataGeneralInfoDTOs;
    }

    /**
     * 获取结果
     *
     * @param warehouseCode
     * @param bigDataPlanSalesEntitys
     * @return {@link List<IndexQuery>}
     **/
    private List<IndexQuery> getResult(String warehouseCode, String skuCode, List<BigdataPredictlyEsEntity> bigDataPlanSalesEntitys) {
        //获取销售计划es历史数据
        List<SalesPlanEsEntity> salesPlanEsEntitys = this.getHistoryOfRequirement(warehouseCode, skuCode);
        if (CollectionUtils.isEmpty(salesPlanEsEntitys)) {
            salesPlanEsEntitys = new ArrayList<>(1);
        }
        return this.handleData(salesPlanEsEntitys, bigDataPlanSalesEntitys);
    }

    private List<IndexQuery> handleData(List<SalesPlanEsEntity> salesPlanEsEntitys, List<BigdataPredictlyEsEntity> bigDataPlanSalesEntitys) {
        //遍历
        int countDirect;
        String skuKey;
        List<SalesPlanEsEntity> tmpSalesPlanEsEntitys;
        List<IndexQuery> queryList = new ArrayList<>();
        //某sku某日期下的总值
        Map<String, BigDecimal> totalValue;
        for (BigdataPredictlyEsEntity bigDataPlanSalesEntity : bigDataPlanSalesEntitys) {
            tmpSalesPlanEsEntitys = new ArrayList<>();
            skuKey = bigDataPlanSalesEntity.getSku_key();
            countDirect = 0;
            for (SalesPlanEsEntity salesPlanEsEntity : salesPlanEsEntitys) {
                //比较sku是否相同
                if (skuKey.equals(salesPlanEsEntity.getSku_key())) {
                    tmpSalesPlanEsEntitys.add(salesPlanEsEntity);
                    countDirect++;
                }
            }
            //更新十三周数据
            if (countDirect != 0) {
                //按照日期排序，计算每个日期下的总量：<date,BigDecimal>
                totalValue = tmpSalesPlanEsEntitys.stream().collect(groupingBy(SalesPlanEsEntity::getStart_date, Collectors.collectingAndThen(Collectors.toList(), values -> values.stream().map(item -> {
                    if (item.getConfirm_l4() == null) {
                        return BigDecimal.ZERO;
                    } else {
                        return item.getConfirm_l4();
                    }
                }).reduce(BigDecimal::add).orElse(BigDecimal.ZERO))));
                for (SalesPlanEsEntity salesPlanEsEntity : tmpSalesPlanEsEntitys) {
                    this.setDirectlyPredictValue(salesPlanEsEntity, totalValue, bigDataPlanSalesEntity);
                    queryList.add(new IndexQueryBuilder().withObject(salesPlanEsEntity).withId(salesPlanEsEntity.getId()).build());
                }
            }
        }
        return queryList;
    }

    private void setDirectlyPredictValue(SalesPlanEsEntity salesPlanEsEntity, Map<String, BigDecimal> totalValue, BigdataPredictlyEsEntity bigDataPlanSalesEntity) {
        //获取对应日期的预测值
        String startDateStr = salesPlanEsEntity.getStart_date();
        BigDecimal total = totalValue.get(startDateStr);
        if (startDateStr1.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_1(), total);
            return;
        }
        if (startDateStr2.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_2(), total);
            return;
        }
        if (startDateStr3.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_3(), total);
            return;
        }
        if (startDateStr4.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_4(), total);
            return;
        }
        if (startDateStr5.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_5(), total);
            return;
        }
        if (startDateStr6.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_6(), total);
            return;
        }
        if (startDateStr7.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_6(), total);
            return;
        }
        if (startDateStr8.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_7(), total);
            return;
        }
        if (startDateStr9.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_9(), total);
            return;
        }
        if (startDateStr10.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_10(), total);
            return;
        }
        if (startDateStr11.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_11(), total);
            return;
        }
        if (startDateStr12.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_12(), total);
        }
        if (startDateStr13.equals(startDateStr)) {
            this.setDirectValue(salesPlanEsEntity, bigDataPlanSalesEntity.getSales_week_f_13(), total);
        }
    }

    private void setDirectValue(SalesPlanEsEntity salesPlanEsEntity, BigDecimal sales, BigDecimal total) {
        //设置上次需求分配量
        salesPlanEsEntity.setLast_require_distribution_qty(salesPlanEsEntity.getRequire_distribution_qty());
        //设置上次需求确认量
        salesPlanEsEntity.setLast_require_confirm_qty(salesPlanEsEntity.getRequire_confirm_qty());
        if (total != null && BigDecimal.ZERO.compareTo(total) != 0) {
            //设置需求分配量
            salesPlanEsEntity.setRequire_distribution_qty(sales.multiply(salesPlanEsEntity.getConfirm_l4()).divide(total, 8, ROUND_HALF_UP));
            //设置需求确认量
            salesPlanEsEntity.setRequire_confirm_qty(salesPlanEsEntity.getRequire_distribution_qty());
        }
    }

    private void setSsDirectValue(SalesPlanEsEntity salesPlanEsEntity, BigDecimal sales, BigDecimal total) {
        //设置上次需求分配量
        salesPlanEsEntity.setLast_require_distribution_qty(salesPlanEsEntity.getRequire_distribution_qty());
        //设置上次需求确认量
        salesPlanEsEntity.setLast_require_confirm_qty(salesPlanEsEntity.getRequire_confirm_qty());
        if (total != null && !BigDecimal.ZERO.equals(total)) {
            //设置需求分配量
            salesPlanEsEntity.setRequire_distribution_qty(sales.multiply(salesPlanEsEntity.getConfirm_l4()).divide(total, 8, ROUND_HALF_UP));
            //设置需求确认量
            salesPlanEsEntity.setRequire_confirm_qty(salesPlanEsEntity.getRequire_distribution_qty());
        }
        // salesPlanEsEntity.setSs(safeStock);
        // salesPlanEsEntity.setSaleInventory(saleInventory);
    }

    private void setGeneralInfo(SalesPlanEsEntity salesPlanEsEntity, BigdataPredictlyEsEntity bigDataGeneralInfoDTO) {
        //设置大中小品类
        salesPlanEsEntity.setCate_l2(bigDataGeneralInfoDTO.getCate_l2());
        salesPlanEsEntity.setCate_l3(bigDataGeneralInfoDTO.getCate_l3());
        salesPlanEsEntity.setCate_l4(bigDataGeneralInfoDTO.getCate_l4());
    }

    /**
     * 获取历史数据
     *
     * @param warehouseCode
     * @return {@link List<SalesPlanEsEntity>}
     **/
    private List<SalesPlanEsEntity> getHistoryOfRequirement(String warehouseCode, String skuCode) {
        final long SCROLL_TIMEOUT = 5 * 60 * 1000;
        // 获取所有周查询条件条件查询
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(
                        QueryBuilders.boolQuery()
                                .filter(rangeQuery(FORMULATE_DATE.getType()).lte(startDateStr13).gte(startDateStr1))
                                .filter(matchQuery(DELIVER_ID.getType(), warehouseCode)).filter(matchQuery(SKU_KEY.getType(), skuCode))
                ).withIndices(BigDataEsConstants.INDEX_NAME_PLAN_SALES_PLAN).withPageable(PageRequest.of(0, 1000)).build();
        ScrolledPage<SalesPlanEsEntity> scroll = (ScrolledPage<SalesPlanEsEntity>) elasticsearchTemplate
                .startScroll(SCROLL_TIMEOUT, searchQuery, SalesPlanEsEntity.class);
        List<SalesPlanEsEntity> salesPlanRequirementEntitys = new ArrayList<>();
        while (scroll.hasContent()) {
            salesPlanRequirementEntitys.addAll(scroll.getContent());
            scroll = (ScrolledPage<SalesPlanEsEntity>) elasticsearchTemplate.continueScroll(
                    scroll.getScrollId(), SCROLL_TIMEOUT, SalesPlanEsEntity.class);
        }
        //根据所有查询条件获取数据
        return salesPlanRequirementEntitys;
    }


    /**
     * 初始化必要的缓存信息
     *
     * @param
     * @return void
     **/
    private void initCacheData(Date date) {
        //注入周和日的处理缓存信息
        BigDataCacheUtil.injectDayCache(date);
        BigDataCacheUtil.injectWeekCache(date);
    }

    /**
     * 判断是否需要触发周数据任务（默认为每周一才能触发）
     *
     * @param
     * @return {@link boolean}
     **/
    private boolean validWeekJob(Date date) {
        return DateUtil.dayOfWeek(date) == 2;
    }
}
